package com.spzx.cart.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.spzx.cart.domain.CartInfo;
import com.spzx.cart.enums.CartCheckedEnum;
import com.spzx.cart.service.CartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.RemoteProductSkuService;
import com.spzx.product.api.domain.dto.ProductSkuDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    // 购物车缓存key
    private static final String CART_INFO = "cart:info:";

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RemoteProductSkuService productSkuService;

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        // 先判断当前用户的购物车中是否已经添加了该商品，若已添加，数值增加
        CartInfo cartInfo;
        Long userId = SecurityUtils.getUserId();
        String cartKey = CART_INFO + userId;
        // 创建hash结构绑定操作对象（方便对hash进行操作）
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        String hashKey = skuId.toString();
        if (hashOps.hasKey(hashKey)) {
            // 购物车中已存有该商品，对数量进行累加，存放数量不超过99
            cartInfo = hashOps.get(hashKey);
            skuNum += cartInfo.getSkuNum();
            if (skuNum > 99) {
                throw new ServiceException("同一件商品，购物车中最多添加99件");
            }
            cartInfo.setSkuNum(skuNum);
        } else {
            // 先判断购物车的商品种类（不同的sku）是否大于50件
            Long count = hashOps.size();
            if (++count > 50) {
                throw new ServiceException("购物车中添加的商品种类超过上限！");
            }
            R<ProductSkuDto> result = productSkuService.getSkuInfoBySkuId(skuId, SecurityConstants.INNER);
            ProductSkuDto productSku = result.getData();
            if (StringUtils.isNull(result) || R.FAIL == result.getCode()) {
                throw new ServiceException("根据skuId查询商品sku信息失败，请稍后再试");
            }
            cartInfo = new CartInfo();
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());
            cartInfo.setSkuNum(skuNum > 99 ? 99 : skuNum);
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setIsChecked(CartCheckedEnum.NOT_CHECKED.getCode());
            cartInfo.setCreateTime(new Date());
        }
        hashOps.put(hashKey, cartInfo);
    }

    @Override
    public List<CartInfo> getAllCart() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = CART_INFO + userId;
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);
        Set<String> skuIds = hashOps.keys();
        if (CollUtil.isEmpty(skuIds)) {
            return new ArrayList<>();
        }
        // 远程查询sku集合的最新价格
        R<Map<Long, BigDecimal>> result = productSkuService.getSkuPrice(skuIds, SecurityConstants.INNER);
        if (StringUtils.isNull(result) || R.FAIL == result.getCode()) {
            throw new ServiceException("根据skuId集合查询商品sku的价格失败，请稍后再试。");
        }
        Map<Long, BigDecimal> priceMap = result.getData();
        List<CartInfo> list = hashOps.values();
        for (CartInfo item : list) {
            item.setSkuPrice(priceMap.get(item.getSkuId()));
        }
        return list;
    }

    @Override
    public void deleteCart(Long skuId) {
        Long userId = SecurityUtils.getUserId();
        if (skuId == null) {
            redisTemplate.delete(CART_INFO + userId);
        } else {
            redisTemplate.opsForHash().delete(CART_INFO + userId, skuId.toString());
        }
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        Long userId = SecurityUtils.getUserId();
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(CART_INFO + userId);
        if (skuId == null) {
            if (CollUtil.isNotEmpty(hashOps.keys())) {
                Map<String, CartInfo> cartInfoMap = hashOps.entries();
                cartInfoMap.forEach((key, value) -> value.setIsChecked(isChecked));
                hashOps.putAll(cartInfoMap);
            }
        } else {
            if (hashOps.hasKey(skuId.toString())) {
                CartInfo cartInfo = hashOps.get(skuId.toString());
                cartInfo.setIsChecked(isChecked);
                hashOps.put(skuId.toString(), cartInfo);
            }
        }
    }

    @Override
    public List<CartInfo> getCartCheckedList() {
        BoundHashOperations<String, String, CartInfo> hashOps =
                redisTemplate.boundHashOps(CART_INFO + SecurityContextHolder.getUserId());
        List<CartInfo> values = hashOps.values();
        List<CartInfo> resultList = values.stream().filter(item -> item.getIsChecked() == 1).collect(Collectors.toList());
        return resultList;
    }

    @Override
    public void updateCartPrice() {
        Long userId = SecurityUtils.getUserId();
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(CART_INFO + userId);
        Set<String> skuIds = hashOps.keys();
        if (CollUtil.isNotEmpty(skuIds)) {
            R<Map<Long, BigDecimal>> result = productSkuService.getSkuPrice(skuIds, SecurityConstants.INNER);
            Map<Long, BigDecimal> priceMap = result.getData();
            if (CollUtil.isNotEmpty(priceMap)) {
                List<CartInfo> list = hashOps.values();
                for (CartInfo item : list) {
                    item.setSkuPrice(priceMap.get(item.getSkuId()));
                    hashOps.put(String.valueOf(item.getSkuId()), item);
                }
            }
        }
    }

    @Override
    public void deleteCartCheckedList() {
        Long userId = SecurityUtils.getUserId();
        BoundHashOperations<String, String, CartInfo> hashOps = redisTemplate.boundHashOps(CART_INFO + userId);
        hashOps.values().forEach(cartInfo -> {
            if (cartInfo.getIsChecked() == 1) {
                hashOps.delete(String.valueOf(cartInfo.getSkuId()));
            }
        });
    }
}